/**
 * Slab 分配器的实现。
 */
#ifndef _AHAMOLETT_SLAB_ALLOCATOR_H_
#define _AHAMOLETT_SLAB_ALLOCATOR_H_

#include <mm/slab_types.h>

/* 最大允许分配的内存对象大小为64KiB。 */
#define SLAB_MAX_OBJ_SIZE   65536
/* 最小允许分配的内存对象大小为8B。 */
#define SLAB_MINIMUN_BOJ_SIZE   8
/* Slab分配器允许最大分配的复合页的阶数。 */
#define SLAB_PAGE_MAX_ORDER 6


/**
 * @brief 创建一个 Slab 分配器。
 * 
 * 跟定给定参数创建一个 Slab 分配器。
 * 
 * 该函数必须在 kmalloc 得到初始化后才能使用，且对齐后的内存对象大小不得大于64KiB。
 * 
 * @param name Slab 分配器的名称，字符串。
 * @param size Slab 中每个内存对象的大小。无论给定什么值，暂时都指定向8字节对齐。
 * @param align Slab 中的内存对象的对齐要求。
 * 
 * @return struct kmem_cache* 创建成功返回指向 Slab 描述符的指针，失败返回NULL。
 */
extern struct kmem_cache *kmem_cache_create(
    const char *name, 
    size_t size, 
    size_t align
);

/**
 * @brief 为一个 Slab 描述符分配新的 Slab 对象。
 * 
 * 新分配一个属于指定 Slab 描述符的 Slab 对象。不会马上加入对应 Slab 描述符的空闲链表内。
 * 
 * @param s Slab 描述符。
 * 
 * @return struct page_struct* 扩展成功返回新分配的 Slab 对象所在复合页的首页，扩展失败
 *                              返回NULL。
 */
extern struct page_struct *__kmem_cache_grow(struct kmem_cache *s);

/**
 * @brief 为一个 Slab 描述符释放一个 Slab 对象。
 * 
 * 尝试从 Slab 描述符的空闲链表中取出一个 Slab 对象并进行释放。
 * 
 * @param s Slab 描述符。
 * 
 * @return int 扩展成功返回0，失败返回-1。
 */
extern int __kmem_cache_shrink(struct kmem_cache *s);

/**
 * @brief 销毁一个 Slab 分配器。
 * 
 * 进行销毁的 Slab 分配器必须有效，且 KMEM_FLAG_STATIC_CACHE 位没有被置位。
 * 
 * 销毁的过程中会强行释放其拥有的所有页结构体等内存空间，操作不当可能导致内存泄露。
 * 
 * @param s Slab 描述符。
 */
extern void kmem_cache_destroy(struct kmem_cache *s);

/**
 * @brief 从给定 Slab 分配器中分配一个内存对象。
 * 
 * @param s Slab 描述符。
 * 
 * @return void* 分配成功返回内存对象的首地址，失败返回NULL。
 */
extern void *kmem_cache_alloc(struct kmem_cache *s);

/**
 * @brief 向给定 Slab 分配器中释放一个内存对象。
 * 
 * @param s Slab 描述符。
 * @param ptr 进行释放的内存对象的虚拟地址。
 */
extern void kmem_cache_free(struct kmem_cache *s, void *ptr);

/**
 * @brief 判断一个 Slab 描述符是否有效。
 * 
 * @param s Slab 描述符。
 * 
 * @retval true 有效。
 * @retval false 无效。
 */
static inline int is_kmem_valid(struct kmem_cache *s)
{
    if (s == NULL) {
        return 0;
    }
    if (!KmemValid(s)) {
        return 0;
    }
    return 1;
}

#endif
